package cn.javass.spring.chapter8;

import java.sql.SQLException;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.jpa.JpaTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import cn.javass.spring.chapter7.UserModel;
import cn.javass.spring.chapter7.dao.IUserDao;


public class JPATest {
    
    private static EntityManagerFactory entityManagerFactory;
    private static ApplicationContext ctx;
    
    @BeforeClass
    public static void setUpClass() {
        String[] configLocations = new String[] {
                "classpath:chapter7/applicationContext-resources.xml",
                "classpath:chapter8/applicationContext-jpa.xml"};
        ctx = new ClassPathXmlApplicationContext(configLocations);
        entityManagerFactory = ctx.getBean(EntityManagerFactory.class);
    }

    @Before
    public void setUp() throws SQLException {
        //id自增主键从0开始
        String createTableSql = "create memory table test" +
        "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +
        "name varchar(100))";
        executeSql(createTableSql);
    }
    @After
    public void tearDown() throws SQLException {
        String dropTableSql = "drop table test";
        executeSql(dropTableSql);
    }
    
    private void executeSql(String sql) throws SQLException {
        EntityManager em = entityManagerFactory.createEntityManager();
        beginTransaction(em);
        em.createNativeQuery(sql).executeUpdate();
        commitTransaction(em);
        closeEntityManager(em);
    }

    @Test
    public void testFirst() throws SQLException {
        UserModel2 model = new UserModel2();
        model.setMyName("test");
        EntityManager em = null;
        try {
            em = entityManagerFactory.createEntityManager();
            beginTransaction(em);
            em.persist(model);
            commitTransaction(em);
        } catch (RuntimeException e) {
            rollbackTransacrion(em);
            throw e;
        }
        finally {
          closeEntityManager(em);
        }
    }
    
    @Test
    public void testJpaTemplate() {
        final JpaTemplate jpaTemplate = new JpaTemplate(entityManagerFactory);
        final UserModel2 model = new UserModel2();
//        final UserModel model2 = new UserModel();
        model.setMyName("test1");
//        model2.setMyName("test2");
        PlatformTransactionManager txManager = ctx.getBean(PlatformTransactionManager.class);
        TransactionTemplate tansactionTemplate = new TransactionTemplate(txManager);
        tansactionTemplate.execute(new TransactionCallback<Void>() {
            @Override
            public Void doInTransaction(TransactionStatus status) {
                jpaTemplate.persist(model);
//                //通过回调允许更复杂操作
//                jpaTemplate.execute(new JpaCallback<Void>() {
//                    @Override
//                    public Void doInJpa(EntityManager em) throws PersistenceException {
//                        em.persist(model2);
//                        return null;
//                    }
//                });
                return null;
            }
        });
        String COUNT_ALL = "select count(*) from UserModel";
        Number count = (Number) jpaTemplate.find(COUNT_ALL).get(0);
        Assert.assertEquals(1, count.intValue());
    }
    
    @Test
    public void bestPracticeTest() {
        String[] configLocations = new String[] {
                "classpath:chapter7/applicationContext-resources.xml",
                "classpath:chapter8/applicationContext-jpa.xml"};
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
        IUserDao userDao = ctx.getBean(IUserDao.class);
        UserModel model = new UserModel();
        model.setMyName("test");
        userDao.save(model);
        Assert.assertEquals(1, userDao.countAll());
    }
    
    
    @Test
    public void crudTest() {
        PlatformTransactionManager txManager = ctx.getBean(PlatformTransactionManager.class);
        final JpaTemplate jpaTemplate = new JpaTemplate(entityManagerFactory);
        TransactionTemplate tansactionTemplate = new TransactionTemplate(txManager);
        tansactionTemplate.execute(new TransactionCallback<Void>() {
            @Override
            public Void doInTransaction(TransactionStatus status) {
                UserModel model = new UserModel();
                model.setMyName("test");
                //新增
                jpaTemplate.persist(model);
                //修改
                model.setMyName("test2");
                jpaTemplate.flush();//可选
                //查询
                String sql = "from UserModel where myName=?";
                List result = jpaTemplate.find(sql, "test2");
                Assert.assertEquals(1, result.size());
                //删除
                jpaTemplate.remove(model);
                return null;
            }
        });
    }
    
    private void closeEntityManager(EntityManager em) {
        em.close();
    }

    private void rollbackTransacrion(EntityManager em) throws SQLException {
        if(em != null) {
            em.getTransaction().rollback();
        }         
    }

    private void commitTransaction(EntityManager em) throws SQLException {
        em.getTransaction().commit();
    }

    private void beginTransaction(EntityManager em) throws SQLException {
        em.getTransaction().begin();
    }
    
    
}
